package com.alvazan.play.logging; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.joda.time.LocalDateTime; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.StackTraceElementProxy; import ch.qos.logback.classic.spi.ThrowableProxyUtil; import ch.qos.logback.core.Appender; import ch.qos.logback.core.AppenderBase; import ch.qos.logback.core.CoreConstants; import ch.qos.logback.core.spi.AppenderAttachable; import ch.qos.logback.core.spi.AppenderAttachableImpl; import com.alvazan.orm.api.base.NoSqlEntityManager; import com.alvazan.orm.api.base.NoSqlEntityManagerFactory; import com.alvazan.orm.api.base.spi.UniqueKeyGenerator; public class CassandraAppender extends AppenderBase<ILoggingEvent> implements AppenderAttachable<ILoggingEvent> { private AppenderAttachableImpl<ILoggingEvent> aai = new AppenderAttachableImpl<ILoggingEvent>(); private int appenderCount; private static String hostname = UniqueKeyGenerator.getHostname(); private int maxLogsEachServer = 100000; private int batchSize = 50; private int counter; private List<LogEvent> inMemoryBuffer = new ArrayList<LogEvent>(); private int errorCount = 0; private static boolean inTryCatch; private static NoSqlEntityManagerFactory factory; public static void setFactory(NoSqlEntityManagerFactory f) { factory = f; } public static boolean isInTryCatch() { return inTryCatch; } public void addAppender(Appender<ILoggingEvent> newAppender) { if (appenderCount == 0) { appenderCount++; addInfo("Attaching appender named [" + newAppender.getName() + "] to appender [" + getName() + "]."); aai.addAppender(newAppender); } else { addWarn("One and only one appender may be attached to CassandraAppender name=[" + getName() + "]."); addWarn("Ignoring additional appender named [" + newAppender.getName() + "]"); } } @Override public void start() { if (appenderCount == 0) { addError("No attached appenders found."); return; } super.start(); } @Override protected void append(ILoggingEvent evt) { if (factory == null) { aai.appendLoopOnAppenders(evt); errorCount++; if (errorCount > 200) { addError("You really need to call CassandraAppender.setFactory to use the Cassandra appender"); } return; } else if(inTryCatch) return; //don't log while in try catch LogEvent logEvt = new LogEvent(); logEvt.setLevel("" + evt.getLevel()); logEvt.setLogger(evt.getLoggerName()); logEvt.setMessage(evt.getMessage()); logEvt.setStackTrace(fullDump(evt)); LocalDateTime t = new LocalDateTime(evt.getTimeStamp()); logEvt.setTime(t); Map<String, String> map = evt.getMDCPropertyMap(); String sid = map.get("sessionid"); logEvt.setSessionId(sid, 2); String user = map.get("user"); logEvt.setUser(user); logEvt.setThreadName(evt.getThreadName()); insert(logEvt); } private synchronized void insert(LogEvent logEvt) { if (counter > maxLogsEachServer) counter = 0; String id = hostname + counter; logEvt.setId(hostname, counter); inMemoryBuffer.add(logEvt); counter++; if (inMemoryBuffer.size() >= batchSize) { flushEvents(); inMemoryBuffer.clear(); } } public String fullDump(ILoggingEvent evt) { try { IThrowableProxy proxy = evt.getThrowableProxy(); if(proxy == null) return null; StringBuilder builder = new StringBuilder(); for (StackTraceElementProxy step : proxy .getStackTraceElementProxyArray()) { String string = step.toString(); builder.append(CoreConstants.TAB).append(string); ThrowableProxyUtil.subjoinPackagingData(builder, step); builder.append(CoreConstants.LINE_SEPARATOR); } return builder.toString(); } catch(Exception e) { addError("exception trying to log exception", e); return "exception parsing exception"; } } public void flushEvents() { try { inTryCatch = true; flushEventsImpl(); } finally { inTryCatch = false; } } public void flushEventsImpl() { NoSqlEntityManager mgr = factory.createEntityManager(); for (LogEvent evt : inMemoryBuffer) { mgr.put(evt, false); } ServersThatLog log = new ServersThatLog(); log.setId(ServersThatLog.THE_ONE_KEY); log.getServers().add(hostname); mgr.put(log); mgr.flush(); mgr.clear(); } public Iterator<Appender<ILoggingEvent>> iteratorForAppenders() { return aai.iteratorForAppenders(); } public Appender<ILoggingEvent> getAppender(String name) { return aai.getAppender(name); } public boolean isAttached(Appender<ILoggingEvent> appender) { return aai.isAttached(appender); } public void detachAndStopAllAppenders() { aai.detachAndStopAllAppenders(); } public boolean detachAppender(Appender<ILoggingEvent> appender) { return aai.detachAppender(appender); } public boolean detachAppender(String name) { return aai.detachAppender(name); } }